package org.dromara.work.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.common.core.domain.event.ProcessEvent;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.service.WorkflowService;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.dromara.work.domain.BaseDmlb;
import org.dromara.work.domain.DmSubmit;
import org.dromara.work.domain.bo.DmBaseComplexSaveBo;
import org.dromara.work.domain.bo.DmBaseQueryBo;
import org.dromara.work.domain.bo.DmGeoSaveBo;
import org.dromara.work.domain.temp.TempDmBase;
import org.dromara.work.domain.temp.TempDmFj;
import org.dromara.work.domain.temp.TempDmGeo;
import org.dromara.work.domain.temp.TempSpatialHighway;
import org.dromara.work.domain.vo.*;

import org.dromara.work.mapper.BaseDmlbMapper;
import org.dromara.work.mapper.DmSubmitMapper;
import org.dromara.work.mapper.temp.TempDmBaseMapper;
import org.dromara.work.mapper.temp.TempDmFjMapper;
import org.dromara.work.mapper.temp.TempDmGeoMapper;

import org.dromara.work.mapper.temp.TempSpatialHighwayMapper;
import org.dromara.work.service.ISpatialAttrBaseService;
import org.dromara.work.service.ITempDmBaseService;
import lombok.RequiredArgsConstructor;
import org.dromara.workflow.domain.TestLeave;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * Author Chen
 * CreateTime 2024/1/15 10:09
 */
@Service
@RequiredArgsConstructor
public class ITempDmBaseServiceImpl implements ITempDmBaseService {


    private final TempDmBaseMapper dmBaseMapper;

    private final TempDmGeoMapper geoMapper;

    private final TempDmFjMapper fjMapper;

    private final DmSubmitMapper submitMapper;

    private final ISysUserService userService;

    private final BaseDmlbMapper dmlbMapper;


    @Override
    public TableDataInfo<DmBaseBriefVo> customPageList(DmBaseQueryBo bo, PageQuery pageQuery) {
        SysUserVo user= userService.selectUserById(LoginHelper.getUserId());
        if(StringUtils.isBlank(bo.getXzqh())){
            if(user.getXzqh()!=null){
                bo.setXzqh(user.getXzqh().toString());
            }
        }
        Page<DmBaseBriefVo> page = dmBaseMapper.selectDmBasePage(pageQuery.build(), bo);
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<DmBaseVo> queryDlPageList(DmBaseQueryBo bo, PageQuery pageQuery) {
        String[] arr=new String[]{"2321","2351"};
        SysUserVo user= userService.selectUserById(LoginHelper.getUserId());
        if(StringUtils.isBlank(bo.getXzqh())){
            if(user.getXzqh()!=null){
                bo.setXzqh(user.getXzqh().toString());
            }
        }
        bo.setDmlbs(arr);
        Page<DmBaseVo> page = dmBaseMapper.selectDlBasePage(pageQuery.build(), bo);
        return TableDataInfo.build(page);
    }

    @Override
    public List<DmBaseVo> queryList(DmBaseQueryBo bo){
        LambdaQueryWrapper<TempDmBase> lqw = buildQueryWrapper(bo);
        List<DmBaseVo> list = dmBaseMapper.selectVoList(lqw);
        return list;
    }

    /**
     * 查询地名属性信息
     */
    @Override
    public DmBaseComplexVo queryBySubmitId(String id){

        DmBaseComplexVo vo=new DmBaseComplexVo();
        //直接调用selectVoById会导致dmlb不显示。实体string型，vo int型。
        TempDmBase base=dmBaseMapper.selectOne(new LambdaQueryWrapper<TempDmBase>().eq(TempDmBase::getSubmitId,id));
        DmSubmit submit=submitMapper.selectById(id);
        DmBaseVo baseVo= BeanUtil.toBean(base, DmBaseVo.class);

        if(baseVo!=null){
            //汇交表的维护类型
            baseVo.setWhlx(submit.getWhlx());
            vo.setBase(baseVo);
            DmGeoVo geo= geoMapper.queryGeoFile(id,baseVo.getCode());
            DmFjVo fj= fjMapper.selectVoOne(new LambdaQueryWrapper<TempDmFj>().eq(TempDmFj::getSubmitId,id));
            if(geo!=null){
                vo.setGeo(geo);
            }
            if(fj!=null){
                vo.setFile(fj);
            }
            //获取实体类，数据工厂里地名类别加了上“temp-”的前缀。
            ISpatialAttrBaseService spatialService= SpatialAttrFactory.getGeoAttrBaseService("temp-"+baseVo.getDmlb().toString());
            if (spatialService != null) {
                vo.setSpatial(spatialService.getAttributeByCode(id));
            }

            //返回流程状态
            //WorkflowUtils.setStatusFieldValue(vo, id);
        }
        return vo;
    }

    /**
     * 查询地名属性信息
     */
    @Override
    public DmBaseFlowComplexVo queryFlowById(String id){

        DmBaseFlowComplexVo vo=new DmBaseFlowComplexVo();
        //直接调用selectVoById会导致dmlb不显示。实体string型，vo int型。
        TempDmBase base=dmBaseMapper.selectOne(new LambdaQueryWrapper<TempDmBase>().eq(TempDmBase::getSubmitId,id));
        DmBaseFlowVo baseVo= BeanUtil.toBean(base, DmBaseFlowVo.class);
        if(baseVo!=null){
            vo.setBase(baseVo);
            DmGeoVo geo= geoMapper.queryGeoFile(id,baseVo.getCode());
            DmFjVo fj= fjMapper.selectVoOne(new LambdaQueryWrapper<TempDmFj>().eq(TempDmFj::getSubmitId,id));
            if(geo!=null){
                vo.setGeo(geo);
            }
            if(fj!=null){
                vo.setFile(fj);
            }
            //获取实体类，数据工厂里地名类别加了上“temp-”的前缀。
            ISpatialAttrBaseService spatialService= SpatialAttrFactory.getGeoAttrBaseService("temp-"+baseVo.getDmlb().toString());
            if (spatialService != null) {
                vo.setSpatial(spatialService.getAttributeLabelByCode(id));
            }
            //返回流程状态
            //WorkflowUtils.setStatusFieldValue(vo, id);
        }
        return vo;
    }


    /**
     * 查询地名属性信息列表
     */
    @Override
    public TableDataInfo<DmBaseVo> queryPageList(DmBaseQueryBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TempDmBase> lqw = buildQueryWrapper(bo);
        Page<DmBaseVo> result = dmBaseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }


    /**
     * 新增地名属性信息
     */
    @Override
    public Boolean insertByBo(DmBaseComplexSaveBo bo) {
        TempDmBase add = BeanUtil.toBean(bo.getBase(), TempDmBase.class);
       // validEntityBeforeSave(add);
        //防止传入ID
        add.setId(null);
        //添加汇交入库表
        DmSubmit submit=new DmSubmit();
        submit.setCode(add.getCode());
        SysUserVo user= userService.selectUserById(LoginHelper.getUserId());
        submit.setSbr(user.getNickName());
        submit.setSblx(user.getRoles().get(0).getRoleKey());
        submit.setSbsj(DateTime.now());
        submit.setUserId(LoginHelper.getUserId());
        submit.setDeptId(LoginHelper.getDeptId());
        if(bo.getTemp()!=null&&!bo.getTemp()){
            //数据类型为变更
            submit.setWhlx("1");
        }
        submitMapper.insert(submit);

        String submitId=submit.getId();
        add.setSubmitId(submitId);
        boolean flag = dmBaseMapper.insert(add) > 0;
        if(flag){
            // 专有属性
            JSONObject spatial= bo.getSpatial();
            // 矢量数据
            DmGeoSaveBo geo=bo.getGeo();
            geo.setCode(add.getCode());
            geo.setCode(add.getCode());
            geo.setName(add.getName());
            geo.setDmlbdm(add.getDmlb());
            geo.setSubmitId(submitId);
            //附件
            TempDmFj fj=BeanUtil.toBean(bo.getFile(),TempDmFj.class);
            fj.setSubmitId(submitId);
            fj.setCode(add.getCode());
            fj.setSfrk(false);
            if(bo.getGeo().getGeom()!=null){
                BaseDmlbVo dmlb=dmlbMapper.selectVoOne(new LambdaQueryWrapper<BaseDmlb>().eq(BaseDmlb::getCode,add.getDmlb()));
                //矢量数据为点类型
                if(dmlb.getType().equals("点")){
                    geoMapper.insertGeoPointEntity(geo);
                }else{
                    geoMapper.insertGeoLineEntity(geo);
                }

            }
            if(spatial!=null){
                saveSpatialAttribute(submitId,add.getCode(),"temp-"+add.getDmlb(),spatial);
            }
            if(fj.getDmzp()!=null){
                fjMapper.insert(fj);
            }
        }
        return flag;
    }

    /**
     * 修改地名属性信息
     */
    @Override
    public Boolean updateByBo(DmBaseComplexSaveBo bo) {
        TempDmBase base = BeanUtil.toBean(bo.getBase(), TempDmBase.class);
        JSONObject spatial = bo.getSpatial();
        boolean flag=true;
        if(base!=null){
            flag=dmBaseMapper.updateById(base)>0;
        }
        // 更新矢量数据
        if(bo.getGeo().getGeom()!=null){

            DmGeoSaveBo geo=bo.getGeo();
            geo.setCode(base.getCode());
            geo.setName(base.getName());
            BaseDmlbVo dmlb=dmlbMapper.selectVoOne(new LambdaQueryWrapper<BaseDmlb>().eq(BaseDmlb::getCode,base.getDmlb()));

            //矢量数据为点类型
            if (dmlb.getType().equals("点")) {
                geoMapper.updateGeoPointEntity(geo);
            } else {
                geoMapper.updateGeoLineEntity(geo);
            }

        }
        //更新专有属性
        if(spatial!=null) {
            updateSpatialAttribute(base.getCode(), "temp-"+base.getDmlb(), spatial);
        }
        //更新附件
        if(bo.getFile().getDmzp()!=null){
            TempDmFj fj=BeanUtil.toBean(bo.getFile(),TempDmFj.class);
            fj.setCode(base.getCode());
            fjMapper.updateById(fj);
        }
        return flag;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave (TempDmBase entity){
        //TODO 做一些数据校验,如唯一约束
        DmBaseQueryBo bo=new DmBaseQueryBo();
        bo.setCode(entity.getCode());
        LambdaQueryWrapper<TempDmBase> lqw = buildQueryWrapper(bo);
        if(!dmBaseMapper.selectVoList(lqw).isEmpty()){
            throw new ServiceException("地名编码已存在！") ;
        }
    }

    /**
     * 批量删除地名属性信息
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        List<String> dmlbList=null;
        List<TempDmBase> baseList= dmBaseMapper.selectList(new LambdaQueryWrapper<TempDmBase>().in(TempDmBase::getSubmitId,ids));
        //删除地名特有属性表
        if(!baseList.isEmpty()){
            dmlbList= baseList.stream().map(e -> String.valueOf( e.getDmlb())).collect(Collectors.toList());

            for(String id:ids){
                for(String dmlb:dmlbList){
                    ISpatialAttrBaseService service = SpatialAttrFactory.getGeoAttrBaseService(dmlb);
                    if (null != service) {
                        service.delAttribute(id);
                    }
                }
            }
        }
        //删除submit表，自动删除地名基础表、矢量数据表。
        return submitMapper.deleteByIds(ids)>0;
    }

    /**
    *  实体查询条件
    */
    private LambdaQueryWrapper<TempDmBase> buildQueryWrapper(DmBaseQueryBo bo) {
        LambdaQueryWrapper<TempDmBase> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getDmlb()), TempDmBase::getDmlb, bo.getDmlb());
        lqw.like(StringUtils.isNotBlank(bo.getName()), TempDmBase::getName, bo.getName());
        lqw.like(StringUtils.isNotBlank(bo.getCode()), TempDmBase::getCode, bo.getCode());
        lqw.like(StringUtils.isNotBlank(bo.getXzqh()), TempDmBase::getCode, bo.getXzqh());
        return lqw;
    }

    private void saveSpatialAttribute(String id,String code,String dmlb,JSONObject spatial) {
        ISpatialAttrBaseService service = SpatialAttrFactory.getGeoAttrBaseService(dmlb);
        if (null == service) {
            throw new BaseException(String.format("不支持类型为%s的地理实体", dmlb));
        }
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        map.put("submit_id",id);
        map.put("data", JSONObject.toJSONString(spatial));
        service.saveAttribute(map);
    }

    private void updateSpatialAttribute(String code,String dmlb,JSONObject spatial) {
        ISpatialAttrBaseService service = SpatialAttrFactory.getGeoAttrBaseService(dmlb);
        if (null == service) {
            throw new BaseException(String.format("不支持类型为%s的地理实体", dmlb));
        }
        Map<String, String> map = new HashMap<>();
        map.put("code", code);
        map.put("data", JSONObject.toJSONString(spatial));
        service.updateAttribute(map);
    }

    /**
     * 总体流程监听(例如: 提交 退回 撤销 终止 作废等)
     * 正常使用只需#processEvent.key=='leave1'
     * 示例为了方便则使用startsWith匹配了全部示例key
     *
     * @param processEvent 参数
     */
    @EventListener(condition = "#processEvent.key.startsWith('dmrk')")
    public void processHandler(ProcessEvent processEvent) {
        //log.info("当前任务执行了{}", processEvent.toString());
        DmSubmit submit = submitMapper.selectById(processEvent.getBusinessKey());
        if(submit!=null){
            submit.setStatus(processEvent.getStatus());
            if (processEvent.isSubmit()) {
                submit.setStatus(BusinessStatusEnum.WAITING.getStatus());
            }
            submitMapper.updateById(submit);
        }
    }
}
